package com.meilai.project.service.business.media.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.dto.system.ImportDeviceByCodeDTO;
import com.meilai.project.dto.system.ImportDeviceByCodeDelDTO;
import com.meilai.project.entity.media.ImportDeviceByCode;
import com.meilai.project.entity.media.ImportDeviceByCodeMp;
import com.meilai.project.entity.media.MediaPoint;
import com.meilai.project.exception.CommonException;
import com.meilai.project.mapper.business.media.ImportDeviceByCodeMapper;
import com.meilai.project.service.business.media.ImportDeviceByCodeMpService;
import com.meilai.project.service.business.media.ImportDeviceByCodeService;
import com.meilai.project.service.business.media.MediaPointService;
import com.meilai.project.vo.business.media.ImportDeviceByCodeVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author 张驰
 * @date 2022/3/15 15:09
 */
@Service
public class ImportDeviceByCodeServiceImpl extends ServiceImpl<ImportDeviceByCodeMapper, ImportDeviceByCode> implements ImportDeviceByCodeService {

    @Autowired
    private MediaPointService mediaPointService;
    @Autowired
    private ImportDeviceByCodeMpService importDeviceByCodeMpService;

    @Override
    public void validDTO(ImportDeviceByCodeDTO dto) {
        if(dto.getCode_length() == null) throw new CommonException("编码总长度不得为空！");
        if(dto.getNumber_start() == null) throw new CommonException("起始数字不得为空！");
        if(dto.getNumber_end() == null) throw new CommonException("结束数字不得为空！");
        if(dto.getNumber_end() < dto.getNumber_start()) throw new CommonException("结束数字不得小于起始数字");
        if(dto.getPrefix() == null) dto.setPrefix("");
        String endStr = String.valueOf(dto.getNumber_end());
        int genLength = dto.getPrefix().length()+endStr.length();
        if(genLength > dto.getCode_length()) throw new CommonException("设定长度小于生成长度！");
    }

    private Set<String> getNotUniqueCodes(ImportDeviceByCode temp){
        int numLength = temp.getCode_length() - temp.getPrefix().length();
        String reg = "";
        if(numLength > 0){
            reg = "^"+temp.getPrefix() + "[0-9]{"+numLength+"}$";
        }else{
            throw new CommonException("数字长度不够！");
        }
        List<String> hasCodes = mediaPointService.getCodeByRegexp(reg);
        List<String> notUniqueCodes = checkCodeUnique(hasCodes, temp.getPrefix(), temp.getNumber_start(), temp.getNumber_end(), numLength);
        return CollectionUtils.isNotEmpty(notUniqueCodes)? new HashSet<String>(notUniqueCodes): new HashSet<String>();
    }

    @Override
    @Transactional
    public Long addRecord(ImportDeviceByCodeDTO dto) {
        int numLength = dto.getCode_length() - dto.getPrefix().length();

        ImportDeviceByCode temp = new ImportDeviceByCode();
        BeanUtils.copyProperties(dto, temp);
        temp.setCode_start(getCode(dto.getPrefix(), dto.getNumber_start(), numLength));
        temp.setCode_end(getCode(dto.getPrefix(), dto.getNumber_end(), numLength));
        temp.setImporting(true);
        save(temp);

        return temp.getId();
    }

    @Override
    @Transactional
    public boolean addOne(ImportDeviceByCodeDTO dto, Long record_id) {
        ImportDeviceByCode temp = getById(record_id);
        Set<String> notUniqueCodes = getNotUniqueCodes(temp);

        int numLength = dto.getCode_length() - dto.getPrefix().length();

        List<MediaPoint> devices = new ArrayList<>();
        long count_except = 0;
        for(long i=dto.getNumber_start();i<=dto.getNumber_end();i++){
            String code = getCode(dto.getPrefix(), i, numLength);
            if(notUniqueCodes.contains(code)){
                count_except++;
            }else{
                String uuid = UUID.randomUUID().toString();

                MediaPoint d = new MediaPoint();
                d.setQrcode(uuid);
                d.setCode(code);
                d.setStatus(0);
                d.setImport_by_code(1);
                devices.add(d);
            }
        }
        mediaPointService.saveBatch(devices);

        List<ImportDeviceByCodeMp> mps = devices.stream().map(d -> {
            ImportDeviceByCodeMp _temp = new ImportDeviceByCodeMp();
            _temp.setImport_id(record_id);
            _temp.setMedia_point_id(d.getId());
            return _temp;
        }).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(mps)) importDeviceByCodeMpService.saveBatch(mps);

        update(Wrappers.<ImportDeviceByCode>lambdaUpdate()
                .set(ImportDeviceByCode::getImporting, false)
                .set(ImportDeviceByCode::getCount_except, count_except)
                .eq(ImportDeviceByCode::getId, record_id));
        return true;
    }

    @Override
    @Transactional
    public boolean delOne(ImportDeviceByCodeDelDTO dto) {

        if(dto.getId() == null) throw new CommonException("查询数据出错，请联系管理员");

        ImportDeviceByCode obj = getById(dto.getId());
        if(obj == null) throw new CommonException("查询不到数据，请联系管理员");

        List<ImportDeviceByCodeMp> mprs = importDeviceByCodeMpService.list(Wrappers.lambdaQuery(ImportDeviceByCodeMp.class).eq(ImportDeviceByCodeMp::getImport_id, dto.getId()));
        if(CollectionUtils.isEmpty(mprs)) throw new CommonException("旧版编号入库，无法删除");

        Set<Long> mpIds = mprs.stream().map(ImportDeviceByCodeMp::getMedia_point_id).collect(Collectors.toSet());
        List<MediaPoint> mps = mediaPointService.listByIds(mpIds);
        if(CollectionUtils.isEmpty(mps)) throw new CommonException("数据出错，相关点位不存在，请联系管理员");

        List<MediaPoint> activeMps = mps.stream().filter(d -> (d.getDeleted_at()==null && d.getStatus()==1)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(activeMps)) throw new CommonException("存在点位已安装，无法删除");

        LocalDateTime now = LocalDateTime.now();
        update(Wrappers.lambdaUpdate(ImportDeviceByCode.class)
                .set(ImportDeviceByCode::getDeleted_at, now)
                .eq(ImportDeviceByCode::getId, dto.getId()));
        mediaPointService.update(Wrappers.lambdaUpdate(MediaPoint.class)
                .set(MediaPoint::getStatus, 0)
                .set(MediaPoint::getDeleted_at, now)
                .in(MediaPoint::getId, mpIds));
        return true;
    }

    private String getCode(String prefix, Long number, Integer num_length){
        StringBuilder pat = new StringBuilder("");
        for(int i=0;i<num_length;i++){
            pat.append("0");
        }
        return prefix+new DecimalFormat(pat.toString()).format(number);
    }

    private List<String> checkCodeUnique(List<String> codes, String prefix, Long number_start, Long number_end, Integer num_length){
        //定义set集合,实现去重效果
        Set<String> result = new HashSet<String>();
        //定义正则表达式
        String regex = "(?<=^"+prefix+")[0-9]{"+num_length+"}$";
        Pattern pattern = Pattern.compile(regex);
        if(CollectionUtils.isNotEmpty(codes)){
            for(String code: codes){
                //匹配文本中每行的字符串
                Matcher matcher = pattern.matcher(code);
                //发现匹配的字符串,存入set中
                while(matcher.find()){
                    long num = Long.parseLong(matcher.group());
                    if(num >= number_start && num <= number_end) result.add(getCode(prefix, num, num_length));
                }
            }
        }
        return new ArrayList<>(result);
    }

    @Override
    public Page<ImportDeviceByCodeVO> selectPageList(Integer current_page, Integer page_size) {
        Page<ImportDeviceByCodeVO> page = new Page<ImportDeviceByCodeVO>(current_page,page_size);
        List<ImportDeviceByCodeVO> list = baseMapper.selectPageList(page);
        return page.setRecords(list);
    }
}
